﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Core.Services
{
	using System;
	using Falcon.Core.Collections;
	using Falcon.Core.Domain;
	using Falcon.Core.Domain.Repositories;
	using Falcon.Core.Domain.Services;
	using Falcon.Core.Domain.Values;
	using Falcon.Core.Extensions;

	public class UserGroupService : IUserGroupService
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="UserGroupService"/> class.
		/// </summary>
		/// <param name="identityService">The identity service.</param>
		/// <param name="userGroupMemberService">The user group member service.</param>
		/// <param name="userGroupCommentService">The user group comment service.</param>
		/// <param name="userGroupPhotoService">The user group photo service.</param>
		/// <param name="userGroupRepository">The user group repository.</param>
		public UserGroupService(
			IIdentityService identityService,
			IUserGroupMemberService userGroupMemberService, 
			IUserGroupCommentService userGroupCommentService,
			IUserGroupPhotoService userGroupPhotoService,
			IUserGroupRepository userGroupRepository)
		{
			this.IdentityService = identityService;
			this.UserGroupMemberService = userGroupMemberService;
			this.UserGroupCommentService = userGroupCommentService;
			this.UserGroupPhotoService = userGroupPhotoService;
			this.UserGroupRepository = userGroupRepository;
		}

		/// <summary>
		/// Gets or sets the identity service.
		/// </summary>
		/// <value>The identity service.</value>
		public IIdentityService IdentityService
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the user group member service.
		/// </summary>
		/// <value>The user group member service.</value>
		public IUserGroupMemberService UserGroupMemberService
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the user group comment service.
		/// </summary>
		/// <value>The user group comment service.</value>
		public IUserGroupCommentService UserGroupCommentService
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the user group photo service.
		/// </summary>
		/// <value>The user group photo service.</value>
		public IUserGroupPhotoService UserGroupPhotoService
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the user group repository.
		/// </summary>
		/// <value>The user group repository.</value>
		public IUserGroupRepository UserGroupRepository
		{
			get; 
			private set;
		}

		/// <summary>
		/// Gets the user group by the specified specification.
		/// </summary>
		/// <param name="specification">The <see cref="UserGroupSpecification"/>.</param>
		/// <returns></returns>
		public UserGroup GetBy(UserGroupSpecification specification)
		{
			var group = UserGroupRepository.GetBy(specification);

			Determine(group);

			return group;
		}

		/// <summary>
		/// Gets the user group by id.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public UserGroup GetById(int id)
		{
			var group = UserGroupRepository.GetById(id);

			Determine(group);

			return group;
		}

		/// <summary>
		/// Gets all the users groups.
		/// </summary>
		/// <param name="specification">The <see cref="UserGroupSpecification"/>.</param>
		/// <returns></returns>
		public IPagedList<UserGroup, UserGroupSpecification> GetPaged(UserGroupSpecification specification)
		{
			var identity = IdentityService.Current;

			if (identity != null)
			{
				specification.MemberId = identity.Id;
			}

			return UserGroupRepository.GetPaged(specification);
		}

		/// <summary>
		/// Creates the user group.
		/// </summary>
		/// <returns></returns>
		public UserGroup Create()
		{
			var group = new UserGroup
			{
				Created = DateTime.Now
			};

			group.Updated = group.Created;

			return group;
		}

		/// <summary>
		/// Populates the specified group members, comments and photos.
		/// </summary>
		/// <param name="group">The group.</param>
		/// <param name="page">The page.</param>
		public void Populate(UserGroup group, int? page)
		{
			group.Members = this.UserGroupMemberService.GetPaged(new UserGroupMemberSpecification
			{
				GroupId = group.Id,
				Page = 1,
				Limit = Settings.Users.GroupMemberMainPageLimit
			});

			group.Comments = this.UserGroupCommentService.GetPaged(new UserGroupCommentSpecification
			{
				GroupId = group.Id,
				Page = page,
				Limit = Settings.Users.GroupCommentPageLimit
			});

			group.Photos = this.UserGroupPhotoService.GetPaged(new UserGroupPhotoSpecification
			{
				GroupId = group.Id,
				Page = 1,
				Limit = Settings.Users.GroupPhotoMainPageLimit
			});
		}

		/// <summary>
		/// Determines the specified group.
		/// </summary>
		/// <param name="group">The group.</param>
		public void Determine(UserGroup group)
		{
			group.IsMember = false;

			var identity = IdentityService.Current;

			if (identity == null)
			{
				return;
			}

			var count = this.UserGroupMemberService.Count(new UserGroupMemberSpecification
			{
				GroupId = group.Id,
				UserId = identity.Id
			});

			group.IsMember = (group.CanView || (count > 0));
		}

		/// <summary>
		/// Inserts the user group into the storage.
		/// </summary>
		/// <param name="group">The group.</param>
		public void Insert(UserGroup group)
		{
			group.Validate();

			group.Slug = group.Title.Slug();

			if (group.Body.HasValue())
			{
				group.BodyParsed = group.Body.BBCodeToHtml(true);
			}

			this.UserGroupRepository.Insert(group);
		}

		/// <summary>
		/// Inserts the user group into the storage.
		/// </summary>
		/// <param name="group">The group.</param>
		/// <param name="value">The value.</param>
		public void Insert(UserGroup group, UserGroupCreate value)
		{
			value.Validate();

			var identity = IdentityService.Current;

			group.UserId = identity.Id;
			group.Title = value.Title;
			group.Body = value.Body;
			group.IsAlbumsEnabled = value.IsAlbumsEnabled;
			group.IsCommentsEnabled = value.IsCommentsEnabled;
			group.IsHidden = value.IsHidden;
			group.Scope = value.Scope;

			this.Insert(group);
		}

		/// <summary>
		/// Updates the user group in the storage.
		/// </summary>
		/// <param name="group">The group.</param>
		public void Update(UserGroup group)
		{
			group.Validate();

			group.Slug = group.Title.Slug();

			if (group.Body.HasValue())
			{
				group.BodyParsed = group.Body.BBCodeToHtml(true);
			}

			this.UserGroupRepository.Update(group);
		}

		/// <summary>
		/// Updates the user group in the storage.
		/// </summary>
		/// <param name="group">The group.</param>
		/// <param name="value">The value.</param>
		public void Update(UserGroup group, UserGroupUpdate value)
		{
			value.Validate();

			group.Title = value.Title;
			group.Body = value.Body;
			group.IsAlbumsEnabled = value.IsAlbumsEnabled;
			group.IsCommentsEnabled = value.IsCommentsEnabled;
			group.IsHidden = value.IsHidden;
			group.Scope = value.Scope;

			this.Update(group);
		}

		/// <summary>
		/// Deletes the user group in the storage.
		/// </summary>
		/// <param name="group">The group.</param>
		public void Delete(UserGroup group)
		{
			this.UserGroupRepository.Delete(group);
		}
	}
}